using System;
using System.Web;
using Drill.Core;
using Drill.LocatorPattern;

namespace Drill.Integration.Web
{
	/// <summary>
	/// Implementation of <see cref="IDependencyResolver"/> that resolves dependencies  
	/// using the ordered list of configured DrillBits and also returns the ASP.NET 
	/// HttpContextBase instance.
	/// </summary>
	public class AspNetDrillChuckDependencyResolver : DrillChuckDependencyResolver
	{
		private readonly ILocator<HttpContextBase> _httpContextLocator;
		private static readonly Type _httpContextBaseType = typeof(HttpContextBase);

		/// <summary>
		/// Initializes a new instance of the <see cref="AspNetDrillChuckDependencyResolver" /> class.
		/// </summary>
		/// <param name="initContext">The initContext.</param>
		public AspNetDrillChuckDependencyResolver(IDependencyResolverInitContext initContext)
			: base(initContext)
		{
			_httpContextLocator = base.GetInstance<ILocator<HttpContextBase>>() ?? new HttpContextLocator();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="AspNetDrillChuckDependencyResolver" /> class.
		/// </summary>
		/// <param name="initContext">The initContext.</param>
		/// <param name="httpContextLocator">The <see cref="ILocator{HttpContextBase}"/> instance.</param>
		public AspNetDrillChuckDependencyResolver(IDependencyResolverInitContext initContext, ILocator<HttpContextBase> httpContextLocator)
			: base(initContext)
		{
			_httpContextLocator = httpContextLocator;
		}

		/// <summary>
		/// Disposes the managed resources.
		/// </summary>
		protected override void DisposeManagedResources()
		{
			_httpContextLocator.Dispose();
			base.DisposeManagedResources();
		}

		/// <summary>
		/// Gets an instance of the type specified by <paramref name="targetType" />.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <returns>
		/// An instance of the requested type.
		/// </returns>
		public override object GetInstance(Type targetType)
		{
			HttpContextBase httpContext = InterceptHttpContextBase(targetType);
			return httpContext ?? base.GetInstance(targetType);
		}

		/// <summary>
		/// Gets the instance.
		/// </summary>
		/// <typeparam name="TTargetType">The type of the target type.</typeparam>
		/// <returns></returns>
		public override TTargetType GetInstance<TTargetType>()
		{
			object httpContext = InterceptHttpContextBase(typeof(TTargetType));
			if (null != httpContext)
			{
				return (TTargetType) httpContext;
			}
			return base.GetInstance<TTargetType>();
		}

		private HttpContextBase InterceptHttpContextBase(Type targetType)
		{
			return (_httpContextBaseType == targetType) ? _httpContextLocator.Locate() : null;
		}
	}
}